#!/bin/bash

set -o errexit
set -o pipefail
#set -o nounset
#set -o xtrace
#export 'PS4=+ $me.$LINENO ';

# replace for your env
image_basepath=/var/tmp
dsapid_url=http://images.itime.biz
dsapid_token=admintoken


# 用法说明
function usage(){
  echo "usage:"
  echo "  $0 <options>"    
  echo "     --vm-name <VMNAME> 要导出image的bhyve虚拟机 名称"
  echo "     --vm-filesystem <VMFILESYSTEM> 要导出image的bhyve虚拟机 文件系统,可选，默认为 zones/${VMNAME}"
  echo "     -n|--image-name <IMAGENAME> 导出的image 名称" 
  echo "     -v|--image-version <IMAGEVERSION> 导出的image 版本"
  echo "     -os|--image-os <IMAGEOS> 镜像操作系统，只能是以下之一：smartos, linux, windows, bsd, illumos, other"
  echo "     -desc|--image-description <IMAGEDESCRIPTION> 镜像描述"
  echo "     --image-size <IMAGESIZE 镜像大小(disk大小）,单位为MB, 可选，默认为源虚拟机磁盘大小或10240"
  echo "     --homepage <HOMEPAGE> 镜像说明网站，可选，默认为 https://docs.joyent.com/images"
  echo "     --image-uuid <IMAGEUUID> 镜像uuid, 可选，如果不提供，会自动新产生一个，必须为uuid，可以用命令uuid来产生"
  echo "     --output-dir <OUTPUTDIR> 导出的image保存目录，可选，默认为/var/tmp" 
  echo ""   
  echo "     --help|-h 显示使用帮助"
  echo ""
  echo "   只适用于用/usr/sbin/bhyve部署的虚拟机"
  echo ""    
  echo "     使用示例："
  echo "          $0 --vm-name ubuntukylin --image-name ubuntukylin-20.04.1"
  echo "              从 名称 为 ubuntukylin 的虚拟机导出image, image命名为: ubuntukylin-20.04.1, 导出文件为: /var/tmp/ubuntukylin-20.04.1.zvol.gz"
  echo "          $0 --vm-name ubuntukylin --image-name ubuntukylin-20.04.1 --ouput-dir /zones/mydir"
  echo "              从uuid为 1e65c912-3123-11eb-a066-4338f21c17e7 的虚拟机导出image, image命名为: ubuntukylin-20.04.1, 导出文件为: /zones/mydir/ubuntukylin-20.04.1.zvol.gz"
  echo "          $0 -h"
  echo "              显示命令使用帮助"
  exit
}

# 出错提示
function fatal(){
  echo ""
  echo "$1"
  exit 1
}

function create_image_file(){
  [[ "${vm_filesystem}" == "" ]] && vm_filesystem="zones/${vm_name}"

  local filesystem_size=$(zfs list -Ho volsize ${vm_filesystem} 2> /dev/null||true)
  [[ "${filesystem_size}" == "" ]] && fatal "不存在filesystem: ${vm_filesystem}"

  if [ "${image_size}" == "" ];then
    local filesystem_size_unit = ${filesystem_size:0,-1}
    local filesystem_size_value = ${filesystem_size:0:-1}
    [[ "${filesystem_size_unit}" == "G" ]] && filesystem_size_value=$((filesystem_size_value*1024))
    image_size=${filesystem_size_value}
  fi

  cd ${image_basepath} 

  echo "create os disk zvol..."
  zfs send ${vm_filesystem} | gzip > ${image_name}.zvol.gz
  zfs destroy ${vm_filesystem}
  echo "bhyvectl --destroy --vm=${vm_name} ..."
  /usr/sbin/bhyvectl --destroy --vm=${vm_name}
  echo "create image at ${image_basepath}/${image_name}.zvol.gz successful!"  
}

function create_image_metafest(){
  local image_gz_file=${image_basepath}/${image_name}.zvol.gz
  local image_gz_sha1=`digest -a sha1 ${image_gz_file}`
  local image_gz_md5=`digest -a md5 ${image_gz_file}`
  local image_gz_size=`ls -l ${image_gz_file} | awk '{print $5}'`
  local image_path=${image_basepath}/${image_uuid}
  mkdir -p ${image_path}
  echo "image file: ${image_path}/${image_name}-${image_version}.zvol.gz"
  ln -sf ${image_gz_file} ${image_path}/${image_name}-${image_version}.zvol.gz
  image_gz_file=${image_name}-${image_version}.zvol.gz

  [[ "${image_size}" == "" ]] && image_size=10240

  echo "create manifest.json..."
  
  publish_time=$(date -u +%Y-%m-%dT%H:%M:%SZ)

  sed '/^[[:blank:]]*$/d' <<-EOF > ${image_path}/manifest.json
{
  "uuid": "${image_uuid}",
  "provider": "community",
  "owner": "a979f956-12cb-4216-bf4c-ae73e6f14dde",
  "name": "${image_name}",
  "version": "${image_version}",
  "description": "${image_description}",
  "homepage": "${homepage}",  
  "state": "active",
  "public": true,
  "disabled": false,
  "type": "zvol",
  "os": "${image_os}",
  "published_at": "${publish_time}",
  "created_at": "${publish_time}",
  "requirements": {
    "networks": [
      {
        "description": "public",
        "name": "net0"
      }
    ],
    "ssh_key": true
  },
  "users": [
    {
      "name": "root"
    }
  ],
  "tags": {
    "role": "os"
  },
  "options": {
    "cpu_type": "host",
    "disk_driver": "virtio",
    "image_size": ${image_size},
    "nic_driver": "virtio"
  },
  "metadata_info": [],
  "builder_info": {},
  "files": [
    {
      "path": "${image_name}-${image_version}.zvol.gz",
      "size": ${image_gz_size},
      "sha1": "${image_gz_sha1}",
      "md5": "${image_gz_md5}",
      "compression": "gzip"
    }
  ]
}
EOF
echo "image manifest: ${image_path}/manifest.json successful"
}

function upload_image(){
  if [ "${dsapid_url}" != "" ];then
    echo "upload image to ${dsapid_url}..."
    curl -v -u ${dsapid_token}: ${dsapid_url}/api/upload -F manifest=@${image_basepath}/${image_uuid}/manifest.json -F file=@${image_basepath}/${image_uuid}/${image_name}-${image_version}.zvol.gz
    echo "upload successful"
  fi
}

# 选项处理
while [[ $# -ge 1 ]]; do
    case $1 in        
        --vm-name )
                vm_name=$2
                shift 2
                ;;
        --vm-filesystem )
                vm_filesystem=$2
                shift 2
                ;;
        -n|--image-name )
                image_name=$2
                shift 2
                ;;
        -v|--image-version )
                image_version=$2
                shift 2
                ;;
        -os|--image-os )
                image_os=$2
                shift 2
                ;;
        -desc|--image-description )
                image_description=$2
                shift 2
                ;;
        --image-size )
                image_size=$2
                shift 2
                ;;
        --homepage )
                homepage=$2
                shift 2
                ;;
        --image-uuid )
                image_uuid=$2
                shift 2
                ;;
        --output-dir )
                image_basepath=$2
                shift 2
                ;;        
        -h|--help )
                usage
                ;;        
        * )
                usage
                ;;
    esac
done


# the image name
[[ "${image_name}" == "" ]] && fatal 'miss -n|--image-name <IMAGENAME>'  
[[ "${image_version}" == "" ]] && fatal 'miss -v|--image-version <IMAGEVERSION>'
[[ "${image_os}" == "" ]] && fatal 'miss -os|--image-os <IMAGEOS>'

[[ "${image_description}" == "" ]] && image_description="${image_os} ${image_name} ${image_version}"
[[ "${homepage}" == "" ]] && homepage="https://docs.joyent.com/images"

if [ "${vm_name}" == "" ];then
  [[ -f ${image_basepath}/${image_name}.zvol.gz ]] || fatal 'miss --vm-name <VMUUID>'
else
  create_image_file
fi

[[ "${image_uuid}" == "" ]] && image_uuid=$(uuid)

create_image_metafest

upload_image